package com.dynamic.mybatis.core.parser.field;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.dynamic.mybatis.core.enums.CommandType;
import com.dynamic.mybatis.core.enums.Type;
import com.dynamic.mybatis.core.exceptions.MybatisFieldValidateException;
import com.dynamic.mybatis.core.metadata.MappedStatementFieldValidator;
import com.dynamic.mybatis.core.metadata.MappedStatementMetaField;
import com.dynamic.mybatis.core.parser.field.DynamicMappedStatementInputParameterFieldParser;
import com.dynamic.mybatis.core.session.DynamicSqlSession;
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException;
import org.apache.ibatis.session.Configuration;

import java.util.*;

public  abstract class DynamicMappedStatementFieldValidator extends DynamicMappedStatementInputParameterFieldParser {

    public DynamicMappedStatementFieldValidator(DynamicSqlSession dynamicSqlSession) {
        super(dynamicSqlSession);
    }

    public  Object validate(List<MappedStatementMetaField> field, CommandType commandType, Object rootParameter, Object parameter){
        if(CollectionUtils.isEmpty(field)){return null;}
        return validate(field.get(0),commandType,rootParameter,parameter);
    }


    public  Object validate(MappedStatementMetaField field, CommandType commandType, Object rootParameter, Object parameter){
        if(field == null){ return  null; }
        return validate(field,null,commandType,rootParameter,parameter);
    }

    public Object validate(MappedStatementMetaField field,String type, CommandType commandType,Object rootParameter, Object parameter){
        MappedStatementFieldValidator validator = field.getValidator();
        if(validator == null || !validator.isEnable()){
            return null;
        }
        if(validator.isRequired() && StringUtils.checkValNull(parameter)
         && !(field.isAutoincrement() && commandType == CommandType.StandardCommand.INSERT)
        ){
            throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s不能为空！");
        }
        if(parameter == null){
            return null;
        }

        type = StringUtils.isNotBlank(type) ?  type : field.getType();

        if (type == Type.StandardType.VARCHAR.type){//字符

            if(parameter != null && !(parameter instanceof String)){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为字符！");

            }else if(field.getValidator().getMinLength() != null && ((String)parameter).length() < field.getValidator().getMinLength().longValue()){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最小长度为"+field.getValidator().getMinLength().longValue());

            }else if(field.getValidator().getMaxLength() != null && ((String)parameter).length() > field.getValidator().getMinLength().longValue()){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最大长度为"+field.getValidator().getMinLength().longValue());
            }

        }else if(Type.NUMBER_TYPES.contains(type)){//数字
            boolean transport;
            if(transport = parameter instanceof String){
                try {
                parameter = NumberUtil.parseNumber((String)parameter);
                }catch (Exception e){
                    throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为数字！");
                }
            }

            if(!(parameter instanceof Number)){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为数字！");

            }else if(field.getValidator().isDigits() && Objects.equals(((Number)parameter).longValue(),parameter)){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为整数！");

            }else if(field.getValidator().getMin() != null && NumberUtil.compare(((Number)parameter).doubleValue(),field.getValidator().getMin().doubleValue()) < 0){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最小值为"+field.getValidator().getMin());

            }else if(field.getValidator().getMax() != null && NumberUtil.compare(((Number)parameter).doubleValue(),field.getValidator().getMax().doubleValue()) > 0){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最大值为"+field.getValidator().getMax());
            }

            if(transport){
                return parameter;
            }

        }else if(Type.DATE_TIME_TYPES.contains(type) && parameter instanceof String){//日期、时间

            try {
              return   DateUtil.parse((String)parameter,validator.getDatePattern());
            }catch (Exception e){
                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "  "+parameter+" "+validator.getDatePattern()+" "+" %s格式有误！");
            }

        }else if(CollectionUtils.isNotEmpty(validator.getEnums()) && !validator.getEnums().containsKey(parameter)){

            throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s未在指定的枚举范围！");

        }else if(Objects.equals(type,Type.StandardType.STRUCT.type) ){ //对象
            if(!(parameter instanceof Map)){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为结构体！");
            }
            if(CollectionUtils.isNotEmpty(field.getChildren())) {
                for (MappedStatementMetaField child : field.getChildren()) {
                   Object result =  validate(child,child.getGenericType(),commandType,rootParameter,((Map)parameter).get(child.getField()));
                   if(result != null){
                       ((Map)parameter).put(child.getField(),result);
                   }
                }
            }

        } else if(Objects.equals(type,Type.StandardType.ARRAY.type) ){//数组

            if(parameter != null && !(parameter instanceof Collection)){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s必须为数组！");

            }else if(field.getValidator().getMinLength() != null && ((Collection)parameter).size() < field.getValidator().getMinLength().longValue()){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最小长度为"+field.getValidator().getMinLength().longValue());

            }else if(field.getValidator().getMaxLength() != null && ((Collection)parameter).size() > field.getValidator().getMinLength().longValue()){

                throw new MybatisFieldValidateException(field,StringUtils.isNotBlank(validator.getErrorMsg()) ? validator.getErrorMsg() : "%s最大长度为"+field.getValidator().getMinLength().longValue());
            }

            List list = ((List) parameter);
            for(int i = 0 ; i < list.size(); i++){
                Object result =  validate(field,field.getGenericType(),commandType,rootParameter,list.get(i));
                if(result != null){
                    ((List)parameter).set(i,result);
                }
            }
        }else if(validator.getRegexPattern() != null && !validator.getRegexPattern().matcher(Objects.toString(parameter,null)).matches()){//正则校验

            throw new MybatisFieldValidateException(field,"%s"+Objects.toString(validator.getErrorMsg(),"校验失败"));

        }else if(validator.getOgnlExpression() != null){ //ognl校验
            try {
                Ognl.getValue(validator.getOgnlExpression(),rootParameter);
            }catch (Exception e){
                throw new MybatisFieldValidateException(field,"%s"+Objects.toString(validator.getErrorMsg(),"校验失败"));
            }
        }
        return null;
    }

    public static void main(String[] args) throws OgnlException {
        Map context = new HashMap();
        context.put("a",1);
        Object value = Ognl.getValue("a", context);




        Map context1 = new HashMap();
        List<Map<String,Object>> ls = new ArrayList();

        Map fc = new HashMap();
        fc.put("a","A01");
        fc.put("b","B01");
        fc.put("c","C01");
        ls.add(fc);

        Map fc2 = new HashMap();
        fc2.put("a","A02");
        fc2.put("b","B02");
        fc2.put("c","C02");
        ls.add(fc2);

        context1.put("list1", ls);

        String val = "B02";
        Object obj = Ognl.getValue(Ognl.parseExpression("list1.{?#this.a.equals(\"A01\") || #this.b=="+val+"}"), context1);
        System.out.println(obj);
    }


}
